/* *****************************************************************************
 * JFab (http://code.google.com/p/jfab)
 * Copyright (c) 2011 JFab.org
 * Admin jfab@jeffreythompson.net
 *
 * See the file "LICENSE.txt" for information on usage and redistribution of
 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
 * *****************************************************************************/

package org.jfab.core;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;
import org.jfab.core.io.CGSpecReader;
import org.jfab.core.io.IOReaderException;
import org.jfab.core.model.CGSpec;

/**
 * Provides a code fabricator.
 */
public class JFabberMain
{
    /**
     * Application method.
     * 
     * @param args Application arguments.
     * 
     * @throws IOException if there is an I/O problem.
     * @throws ParseException if there is a parsing problem.
     */
    public static final void main(final String[] args) throws IOException,
            ParseException
    {
        final Options options = createOptions();
        final CommandLineParser parser = new PosixParser();
        final CommandLine commandLine = parser.parse(options, args);

        if (commandLine.hasOption('h'))
        {
            printHelp(options);
        }
        else if (commandLine.hasOption('f'))
        {
            final File outputDirectory = new File(
                    determineOutputDirectory(commandLine));
            final String filename = commandLine.getOptionValue('f');
            final CGSpec cgSpec = readCgRoot(filename);

            final Injector injector = new DefaultInjector();
            final JFabber codeGenerator = injector.injectJFabber();
            codeGenerator.generateCodeFiles(cgSpec, outputDirectory);
        }
        else
        {
            throw new IllegalArgumentException("Option f must be specified.");
        }
    }

    /**
     * @return application command line options.
     */
    private static final Options createOptions()
    {
        final Options answer = new Options();

        final Option help = new Option("h", "print this message");

        OptionBuilder.withArgName("filename");
        OptionBuilder.hasArg();
        OptionBuilder
                .withDescription("file containing a list of fully qualified class names, one per line");

        final Option filename = OptionBuilder.create("f");

        OptionBuilder.withArgName("directory");
        OptionBuilder.hasArg();
        OptionBuilder.withDescription("output directory");

        final Option directory = OptionBuilder.create("d");

        answer.addOption(help);
        answer.addOption(filename);
        answer.addOption(directory);

        return answer;
    }

    /**
     * @param commandLine Command line.
     * 
     * @return output directory.
     */
    private static final String determineOutputDirectory(
            final CommandLine commandLine)
    {
        String answer = "";

        final char option = 'd';

        if (commandLine.hasOption(option))
        {
            answer = commandLine.getOptionValue(option);
        }

        return answer;
    }

    /**
     * Print the help text.
     * 
     * @param options Command line options.
     */
    private static final void printHelp(final Options options)
    {
        // Automatically generate the help statement.
        final HelpFormatter formatter = new HelpFormatter();
        formatter.printHelp("java [-cp <classpath>] org.jfab.core.JFabber",
                options);
    }

    /**
     * @param filename Filename.
     * 
     * @return a code generator root from the given parameter.
     */
    private static final CGSpec readCgRoot(final String filename)
    {
        CGSpec answer = null;

        Reader reader = null;

        try
        {
            reader = new FileReader(filename);

            final CGSpecReader jfabReader = new CGSpecReader();
            answer = jfabReader.read(reader);
        }
        catch (final FileNotFoundException e)
        {
            throw new IOReaderException(e);
        }
        catch (final Exception e)
        {
            throw new IOReaderException(e);
        }
        finally
        {
            if (reader != null)
            {
                try
                {
                    reader.close();
                }
                catch (final IOException ignore)
                {
                    // Nothing to do.
                }
            }
        }

        return answer;
    }
}
